package cn.iocoder.yudao.framework.handlermapping;

import cn.iocoder.yudao.framework.server.websocket.security.WebSocketUser;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 和当前连接绑定的上下文数据存储类
 *
 * @author 王广帅
 * @version 1.0.0
 * @since 2024/8/28 11:27
 */
@Slf4j
public class WsSessionContext {

    private Map<String, Object> session = new ConcurrentHashMap<>();

    private WebSocketUser webSocketUser;

    private String sessionId;

    private final Object lock = new Object();

    public <T> T getWithTimeout(String key, long timeoutMillis) throws InterruptedException {
        long endTime = System.currentTimeMillis() + timeoutMillis;

        synchronized (lock) {
            while (true) {
                Object value = session.get(key);
                if (value != null) {
                    return (T) value;
                }

                long remaining = endTime - System.currentTimeMillis();
                if (remaining <= 0) {
                    return null; // 超时返回null
                }

                lock.wait(remaining); // 等待直到被通知或超时

                value = session.get(key);
                if (value != null) {
                    log.info("从netty的session中获取到数据, key = {}, value = {}", key, value);
                    return (T) value;
                }
            }
        }
    }

    // 当值被放入map时调用
    public void putAndNotify(String key, Object value) {
        session.put(key, value);
        log.info("添加数据到netty的session, key = {}, value = {}", key, value);
        synchronized (lock) {
            lock.notifyAll(); // 通知所有等待线程
        }
    }

    public void addSessionValue(String key, Object value) {
        this.session.put(key, value);
    }

    public <T> T getSessionValue(String key) {
        if (session.containsKey(key)) {
            return (T) session.get(key);
        }
        return null;
    }

    public String getSessionId() {
        return sessionId;
    }

    public void setSessionId(String sessionId) {
        this.sessionId = sessionId;
    }

    public WebSocketUser getWebSocketUser() {
        return webSocketUser;
    }

    public void setWebSocketUser(WebSocketUser webSocketUser) {
        this.webSocketUser = webSocketUser;
    }

    @Override
    public String toString() {
        return "WsSessionContext{" +
                "session=" + session +
                ", webSocketUser=" + webSocketUser +
                ", sessionId='" + sessionId + '\'' +
                ", lock=" + lock +
                '}';
    }
}
